#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if_arp.h>
#include <sys/timeb.h>
#include <time.h>
#include <pcap.h>
#include <string.h>
#include <unistd.h>
typedef struct pacdata
{
  char s_ip[16], d_ip[16];
  uint8_t s_port, d_port;
  uint8_t proto;
} pacdata;

typedef struct dlist
{
  struct dlist *Last;
  pacdata data;
  struct dlist *next;
} dlist;

void dlistAdd(dlist **head, pacdata data);
void got_packet(unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet);
dlist *head = NULL;
int main(int argc, char *argv[])
{
  if (argc < 2)
  {
    printf("Usage: ./main interface or ./mian filename.pcap\n");
    return -1;
  }

  char PAname[100];
  strncpy(PAname, argv[1], sizeof(PAname) - 1);
  PAname[sizeof(PAname) - 1] = '\0';
  pcap_t *handle;
  char errbuf[PCAP_ERRBUF_SIZE];
  struct bpf_program fp; /* The compiled filter expression */
  printf("\n Starting capture on interface ...\n");

  // 捕获方式判断：文件捕获还是网卡数据包

  if (access(PAname, 0) != -1)
  {
    handle = pcap_open_offline(PAname, errbuf);
    if (handle == NULL)
    {
      fprintf(stderr, "Could not open file %s: %s\n", PAname, errbuf);
      exit(EXIT_FAILURE);
    }
  }
  else
  {
    handle = pcap_open_live(PAname, BUFSIZ, 1, 1000, errbuf);
    if (handle == NULL)
    {
      printf("open live failed.\r\n");
      getchar();
      return -1;
    }
  }

  /* Compile and apply the filter to the packet capture */
  if (pcap_compile(handle, &fp, "", 0, PCAP_NETMASK_UNKNOWN) == -1)
  {
    fprintf(stderr, "Error compiling filter: %s\n", pcap_geterr(handle));
    exit(EXIT_FAILURE);
  }
  if (pcap_setfilter(handle, &fp) == -1)
  {
    fprintf(stderr, "Error setting filter: %s\n", pcap_geterr(handle));
    exit(EXIT_FAILURE);
  }

  // 设置回调函数，每接收到一个数据包就会调用一次回调函数
  int num_packets = -1; // 要求抓取的数据包数量，-1为无限制
  if (pcap_loop(handle, num_packets, got_packet, NULL) < 0)
  {
    perror("pcap_loop error!\n");
    return -1;
  }
  pcap_close(handle);
  // 读链表数据
  dlist *pt = head;
  uint32_t count = 0;
  do
  {
    printf("no.%02i : s_ip = %-15s, d_ip = %-15s, s_port = %-5i, d_port = %-5i , proto = %-3i \n",++count,pt->data.s_ip,pt->data.d_ip,pt->data.s_port,pt->data.d_port,pt->data.proto);
    pt=pt->next;
  } while (pt != NULL);
  
  printf("\n Capture complete.\n");
  return 0;
}
void dlistAdd(dlist **head, pacdata data)
{
  /* 创建新的节点，并分配空间 */
  dlist *new_node = (dlist *)malloc(sizeof(dlist));
  new_node->data = data;
  new_node->next = NULL;
  if (*head == NULL)
  {
    *head = new_node;
    return;
  }
  dlist *pt = *head;
  // 定位到最后一个node 节点进行下一步操作
  while (pt->next != NULL){
    pt = pt->next;
  }
  // new_node->Last = pt;
  pt->next = new_node;
}

void got_packet(unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet)
{
  // printf("packet data = ");
  // for (size_t i = 0; i < header->len; i++)
  // {
  //   printf("%02x", packet[i]);
  // }
  char s_ip[16], d_ip[16];
  sprintf(s_ip, "%d.%d.%d.%d", (int)packet[26], (int)packet[27], (int)packet[28], (int)packet[29]);
  sprintf(d_ip, "%d.%d.%d.%d", (int)packet[30], (int)packet[31], (int)packet[32], (int)packet[33]);
  pacdata newdata = {0};
  strcpy(newdata.s_ip, s_ip);
  strcpy(newdata.d_ip, d_ip);
  newdata.s_port = ((unsigned short)packet[34] << 8) | packet[35];
  newdata.d_port = ((unsigned short)packet[36] << 8) | packet[37];
  newdata.proto = packet[23];
  dlistAdd(&head, newdata);
}